package com.dai.spec.gxk.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dai.spec.common.constant.ColumnConstants;
import com.dai.spec.common.core.domain.entity.SysUser;
import com.dai.spec.common.enums.CourseStatus;
import com.dai.spec.common.enums.DeliveryType;
import com.dai.spec.common.enums.SelectStatus;
import com.dai.spec.common.exception.base.BaseException;
import com.dai.spec.common.utils.SecurityUtils;
import com.dai.spec.gxk.domain.Course;
import com.dai.spec.gxk.domain.CourseSelectionLimit;
import com.dai.spec.gxk.domain.StudentCourse;
import com.dai.spec.gxk.mapper.CourseMapper;
import com.dai.spec.gxk.mapper.SelectedCourseMapper;
import com.dai.spec.gxk.request.PageRequest;
import com.dai.spec.gxk.service.CourseService;
import com.dai.spec.gxk.service.SelectedCourseService;
import com.dai.spec.gxk.service.SelectionLimitService;
import com.dai.spec.gxk.vo.SelectedCourseVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Service
@Slf4j
public class SelectedCourseServiceImpl extends ServiceImpl<SelectedCourseMapper, StudentCourse> implements SelectedCourseService {

    private CourseMapper courseMapper;

    private SelectedCourseMapper selectedCourseMapper;

    private CourseService courseService;
    private SelectionLimitService selectionLimitService;

    private final String LEAVE_COUNTS_SUB1_SQL ="leave_counts = leave_counts - 1";
    private final String LEAVE_COUNTS_ADD1_SQL ="leave_counts = leave_counts + 1";

    public SelectedCourseServiceImpl(CourseMapper courseMapper, SelectedCourseMapper selectedCourseMapper, CourseService courseService,SelectionLimitService selectionLimitService) {
        this.courseMapper = courseMapper;
        this.selectedCourseMapper = selectedCourseMapper;
        this.courseService = courseService;
        this.selectionLimitService = selectionLimitService;
    }

    /**
     * 学生选课
     *
     * @param courseId
     * @return
     */
    //todo 加redis锁
    @Override
    @Transactional
    public int saveSelectedCourse(Long courseId) {
        //获取当前登录用户,一人选一个单独的课程一次
        SysUser user = SecurityUtils.getLoginUser().getUser();
        LambdaQueryWrapper<Course> queryWrapper = new LambdaQueryWrapper<>();
        if (null != courseId) {
            queryWrapper.eq(Course::getId, courseId);
        }
        Course course = courseMapper.selectOne(queryWrapper);
        if (CourseStatus.CLOSE.getCode().equals(course.getStatus())) {
            throw new BaseException("当前课程状态为关闭，未到选课时间或以过选课时间!");
        }
        if (CourseStatus.FULL.getCode().equals(course.getStatus())) {
            throw new BaseException("当前课程已选满，不能进行选择！");
        }
        if (course.getLeaveCounts() == 0) {
            throw new BaseException("当前课程已经选完,不能进行选择!");
        }
        //学生选课
        StudentCourse studentCourse = new StudentCourse();
        String userName = getAdminUserName(user);
        //查询当前学生是否已选择该课程 且选课状态不为已选课
        Long count = query().eq(ColumnConstants.STUDENT_NUMBER, userName)
                .eq(ColumnConstants.COURSE_ID, courseId)
                .eq(ColumnConstants.SELECT_STATUS, SelectStatus.SELECTED.getCode())
                .count();
        //该学生已选择该课程
        if (count > 0) {
            log.error("该用户已选择过一次该课程");
            throw new BaseException("该课程已选择过！");
        }
        List<CourseSelectionLimit> list = selectionLimitService.list();
        CourseSelectionLimit selectionLimit = list.get(0);
        Integer offlineLimit = selectionLimit.getOfflineLimit();
        Long offline = Long.parseLong(offlineLimit.toString());
        Integer onlineLimit = selectionLimit.getOnlineLimit();
        Long online = Long.parseLong(onlineLimit.toString());
        Integer totalLimit = selectionLimit.getTotalLimit();
        Long total = Long.parseLong(totalLimit.toString());
        //在选课区间，一名学生只能选一个线下课程/线上课程
        Long selectedCounts = query().eq(ColumnConstants.STUDENT_NUMBER, userName)
                .eq(ColumnConstants.SELECT_STATUS, SelectStatus.SELECTED.getCode())
                .count();
        String deliveryType = course.getDeliveryType();
        //线上
        if (DeliveryType.ONLINE.getCode().equals(deliveryType)){
          if (selectedCounts >= online){
              throw  new BaseException("选择的线上课程已达上限");
          }
        }
        //线下
        if (DeliveryType.OFFLINE.getCode().equals(deliveryType)){
            if (selectedCounts >= offline){
                throw new BaseException("选择的线上课程已达上限");
            }
        }
//        if (selectedCounts == 1){
//            throw new BaseException("选课期间学生只能选一门课程！");
//        }
        //选择课程后，课程剩余数量-1
        boolean success = courseService.update()
                .setSql(LEAVE_COUNTS_SUB1_SQL)
                .eq(ColumnConstants.ID, courseId).eq(ColumnConstants.STATUS, CourseStatus.OPEN.getCode())
                .update();
        if (!success) {
            //扣减失败
            log.error("课程余量不足！");
            throw new BaseException("课程余量不足！");
        }
        if (course.getLeaveCounts() == 0) {
            //如果课程余量=0，将课程状态设置为已满"2"
            LambdaUpdateWrapper<Course> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Course::getId, courseId)
                    .set(Course::getStatus,CourseStatus.FULL.getCode());
            courseMapper.update(null, updateWrapper);

        }

        //学生学号、课程id、选课状态、成绩
        //todo admin测试 后续修改
        studentCourse.setStudentNumber(Long.parseLong(userName));
        studentCourse.setCourseId(courseId);
        studentCourse.setSelectStatus(SelectStatus.SELECTED.getCode());//已选择
        studentCourse.setScore(new BigDecimal(0));
        //设置选课时间
        studentCourse.setSelectTime(LocalDateTime.now());
//        boolean save = selectedCourseService.save(studentCourse);
        int rows = selectedCourseMapper.insert(studentCourse);
        return rows;
    }

    /**
     * 学生退课
     *
     * @param courseId
     * @return
     */
    @Override
    public int dropSelectedCourse(Long courseId) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        LambdaQueryWrapper<Course> queryWrapper = new LambdaQueryWrapper<>();
        //查询当前课程是否存在
        if (null != courseId) {
            queryWrapper.eq(Course::getId, courseId);
        }
        Course course = courseMapper.selectOne(queryWrapper);
        if (null == course) {
            throw new BaseException("该课程不存在!");
        }
        //课程状态为关闭
        if (CourseStatus.CLOSE.getCode().equals(course.getStatus())) {
            throw new BaseException("该课程状态为关闭，未到选课时间或已过选课时间!");
        }
        String userName = getAdminUserName(user);
        Long count = query().eq(ColumnConstants.STUDENT_NUMBER, userName)
                .eq(ColumnConstants.COURSE_ID, courseId)
                .eq(ColumnConstants.SELECT_STATUS, SelectStatus.SELECTED.getCode())
                .count();
        //该学生是否已选择该课程
        if (count == 0) {
            log.error("该用户没有选择过该课程");
            throw new BaseException("未选择过该课程，无法进行退课操作！");
        }
        if (course.getPlantCounts() == course.getLeaveCounts()) {
            throw new BaseException("课程余量已满，不能进行退课！");
        }
        //退选该课程后，课程剩余数量+1
        boolean success = courseService.update()
                .setSql(LEAVE_COUNTS_ADD1_SQL)
                .eq(ColumnConstants.ID, courseId)
//                .eq("status", "0")//开放
//                .eq("status", "2")//已满
                .ne(ColumnConstants.STATUS, CourseStatus.CLOSE.getCode())
                .update();
        if (!success) {
            //增加失败
            log.error("课程状态为关闭，已过退课时间，不能进行退课！");
            throw new BaseException("课程状态为关闭，已过退课时间，不能进行退课！");
        }
        //退完课后，如果该课程状态为已满，则设置为开放"0"
        if (CourseStatus.FULL.getCode().equals(course.getStatus())) {
            LambdaUpdateWrapper<Course> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Course::getId, courseId)
                    .set(Course::getStatus, CourseStatus.OPEN.getCode());
            courseMapper.update(null, updateWrapper);
        }
        //更新学生选课表 课程状态为"1"已退课
        LambdaUpdateWrapper<StudentCourse> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(StudentCourse::getStudentNumber, Long.parseLong(userName))
                .eq(StudentCourse::getCourseId, courseId)
                .set(StudentCourse::getSelectStatus, SelectStatus.RETIRED.getCode())
                .set(StudentCourse::getDropTime, LocalDateTime.now());
        int rows = selectedCourseMapper.update(null, updateWrapper);
        return rows;
    }

    //todo admin测试，后续删除
    private static String getAdminUserName(SysUser user) {
        String userName = user.getUserName();
        if ("admin".equals(userName)) {
            userName = "123456";
        }
        return userName;
    }


    /**
     * 分页查询已选课程列表
     *
     * @param
     * @return
     */
    @Override
    public List<SelectedCourseVO> querySelectedCourseList(PageRequest pageRequest) {

        PageHelper.startPage(pageRequest.getPageNum(),pageRequest.getPageSize());
        SysUser user = SecurityUtils.getLoginUser().getUser();
        String studentNumber = getAdminUserName(user);
        pageRequest.setStudentNumber(Long.parseLong(studentNumber));
        Page<SelectedCourseVO> selectedCourseVOPage = selectedCourseMapper.querySelectedCourseList(pageRequest);

        return selectedCourseVOPage;
    }

}
